﻿using Stepon.FaceRecognization;
using Stepon.FaceRecognization.Common;
using Stepon.FaceRecognization.Detection;
using Stepon.FaceRecognization.Extensions;
using Stepon.FaceRecognization.Interfaces;
using Stepon.FaceRecognization.Recognization;
using System;
using System.Collections.Generic;
using System.Drawing;
using System.Drawing.Imaging;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace attendanceDemo
{
    class Faces
    {
        private const string appid = "pdhEENp6Ph69tmrMaF6tUP38FJRYXKpqGymPpVinW23";
        private const string ftkey = "BmhbXf2xbRidcP5AZEwbsRQGQk4jPCa5Q3bNajbAWZFD";
        private const string fdkey = "BmhbXf2xbRidcP5AZEwbsRQPa9KriVoaacPSnXUpELWv";
        private const string frkey = "BmhbXf2xbRidcP5AZEwbsRQtDkNZ53iWJMNdM33XLWfa";

        private readonly Dictionary<string, byte[]> faceCache = new Dictionary<string, byte[]>();
        private static FaceLocator faceTracking = LocatorFactory.GetTrackingLocator(appid, ftkey);
        private static FaceDetection faceDetection = LocatorFactory.GetDetectionLocator(appid, fdkey) as FaceDetection;
        private static FaceRecognize faceRecognize = new FaceRecognize(appid, frkey);
        private static FaceProcessor faceProcessor = new FaceProcessor(faceTracking, faceRecognize);

        public void AddFaceToCache(string name, byte[] bytes) {
            faceCache.Add(name, bytes);
        }

        public Boolean FaceTracking(Bitmap bitmap) {
            var result = faceTracking.Detect(bitmap, out var locateResult);
            using (locateResult)
            {
                if (result == ErrorCode.Ok && locateResult.FaceCount > 0)
                {
                    using (var g = Graphics.FromImage(bitmap))
                    {
                        for (var i = 0; i < locateResult.FaceCount; i++)
                        {
                            var face = locateResult.Faces[i].ToRectangle();
                            g.DrawRectangle(new Pen(Color.Chartreuse), face.X, face.Y, face.Width, face.Height);
                        }
                        return locateResult.FaceCount > 0;
                    }
                }
            }
            return false;
        }

        public string FaceRecognize(Bitmap bitmap) {
            string name = "";
            ErrorCode code = faceDetection.Detect(bitmap, out var locate);
            if (code == ErrorCode.Ok && locate.HasFace && locate.FaceCount > 0)
            {
                for (var i = 0; i < locate.FaceCount; i++) {
                    var feature = faceRecognize.ExtractFeature(locate.OffInput, locate.Faces[i], locate.FacesOrient[i]);
                    if (feature == null) {
                        locate.Dispose();
                        return name;
                    }
                    float max = 0;
                    foreach (var single in faceCache) {
                        var sim = faceProcessor.Match(feature.FeatureData, single.Value); //此方法默认保留采集到的特征（非托管内存），并自动释放被比较（特征库）的特征数据，所以无需担心内存泄露
                        if (sim > 0.5 && sim > max)
                        {
                            max = sim;
                            name = single.Key;
                        }
                    }

                    if (name.Length > 0) {
                        locate.Dispose();
                        return name;
                    }
                }
            }
            locate.Dispose();
            return name;
        }

        public byte[] FaceFeatureData(Bitmap bitmap) {
            var code = faceDetection.Detect(bitmap, out var locate);
            if (code == ErrorCode.Ok && locate.HasFace && locate.FaceCount == 1) {
                var feature = faceRecognize.ExtractFeature(locate.OffInput, locate.Faces[0], locate.FacesOrient[0]);
                byte[] bytes = feature.FeatureData.Data;
                locate.Dispose();
                return bytes;
            }
            return null;
        }

        public byte[] BitmapByte(Bitmap bitmap)
        {
            using (MemoryStream stream = new MemoryStream())
            {
                bitmap.Save(stream, ImageFormat.Jpeg);
                byte[] data = new byte[stream.Length];
                stream.Seek(0, SeekOrigin.Begin);
                stream.Read(data, 0, Convert.ToInt32(stream.Length));
                return data;
            }
        }

        public Bitmap ZoomImage(Bitmap SourceImage, int TargetWidth, int TargetHeight)
        {
            int IntWidth; //新的图片宽
            int IntHeight; //新的图片高
            try
            {
                System.Drawing.Imaging.ImageFormat format = SourceImage.RawFormat;
                System.Drawing.Bitmap SaveImage = new System.Drawing.Bitmap(TargetWidth, TargetHeight);
                Graphics g = Graphics.FromImage(SaveImage);
                g.Clear(Color.Black);

                //计算缩放图片的大小 http://www.cnblogs.com/roucheng/

                if (SourceImage.Width > TargetWidth && SourceImage.Height <= TargetHeight)//宽度比目的图片宽度大，长度比目的图片长度小
                {
                    IntWidth = TargetWidth;
                    IntHeight = (IntWidth * SourceImage.Height) / SourceImage.Width;
                }
                else if (SourceImage.Width <= TargetWidth && SourceImage.Height > TargetHeight)//宽度比目的图片宽度小，长度比目的图片长度大
                {
                    IntHeight = TargetHeight;
                    IntWidth = (IntHeight * SourceImage.Width) / SourceImage.Height;
                }
                else if (SourceImage.Width <= TargetWidth && SourceImage.Height <= TargetHeight) //长宽比目的图片长宽都小
                {
                    IntHeight = SourceImage.Width;
                    IntWidth = SourceImage.Height;
                }
                else//长宽比目的图片的长宽都大
                {
                    IntWidth = TargetWidth;
                    IntHeight = (IntWidth * SourceImage.Height) / SourceImage.Width;
                    if (IntHeight > TargetHeight)//重新计算
                    {
                        IntHeight = TargetHeight;
                        IntWidth = (IntHeight * SourceImage.Width) / SourceImage.Height;
                    }
                }
                Font drawFont = new Font("Arial", 16);
                SolidBrush drawBrush = new SolidBrush(Color.Red);
                PointF drawPoint = new PointF(20.0F, 20.0F);
                g.DrawString(DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.ffff"), drawFont, drawBrush, drawPoint);
                g.DrawImage(SourceImage, (TargetWidth - IntWidth) / 2, (TargetHeight - IntHeight) / 2, IntWidth, IntHeight);
                SourceImage.Dispose();
                drawFont.Dispose();
                drawBrush.Dispose();
                return SaveImage;
            }
            catch (Exception ex)
            {

            }

            return null;
        }
    }
}
